package com.yimicloud.common.freemarker;

import com.yimicloud.common.system.ContextHelper;
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * Created by Justin on 2015/9/7.
 */
public class CodeGenerator {
    private Configuration config = new Configuration();
    private File templateDir;
    private File destDir;
    private String applicationName;
    public static String SLASH = "/";
    private Map<String, Object> paramsMap = new HashMap();

    public File getTemplateDir() {
        return this.templateDir;
    }

    public void setTemplateDir(File templateDir) {
        this.templateDir = templateDir;
    }

    public void addParam(String key, Object value) {
        this.paramsMap.put(key, value);
    }

    public void addParam(Map<String, String> map) {
        this.paramsMap.putAll(map);
    }

    public String getApplicationName() {
        return this.applicationName;
    }

    public void setApplicationName(String applicationName) {
        this.applicationName = applicationName;
    }

    public File getDestDir() {
        if(this.destDir == null) {
            String str = "";
            Properties prop = (new ContextHelper()).getSystemProps();
            if(System.getProperty("os.name").toUpperCase().indexOf("LINUX") > -1) {
                str = prop.getProperty("code.template.import.path.linux");
            } else if(System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") > -1) {
                str = prop.getProperty("code.template.import.path.windows");
            }

            this.destDir = new File(str.trim() + SLASH + this.applicationName);
            System.out.println("application out path====>" + this.destDir);
            if(!this.destDir.exists()) {
                this.destDir.mkdirs();
            }
        }

        return this.destDir;
    }

    public CodeGenerator(File templateDir, Map<String, String> map) {
        this.config.setBooleanFormat("true,false");
        this.config.setDefaultEncoding("utf-8");
        this.config.setNumberFormat("##########");
        this.config.setOutputEncoding("utf-8");
        this.templateDir = templateDir;
        this.addParam(map);
    }

    public boolean generateCode() {
        ArrayList origFiles = new ArrayList();

        try {
            FileHelper.listFiles(this.templateDir, origFiles);
            Iterator var3 = origFiles.iterator();

            while(var3.hasNext()) {
                File e = (File)var3.next();
                if(e.isFile()) {
                    String suffix = FileHelper.getFileSuffix(e);
                    if(e.getParentFile().isDirectory()) {
                        this.createDir(e.getParentFile());
                    }

                    if("ftl".equalsIgnoreCase(suffix)) {
                        this.generateFile(e);
                    } else {
                        FileHelper.copyFile(e, this.getDestFile(e));
                    }
                } else {
                    this.createDir(e);
                }
            }

            return true;
        } catch (Exception var5) {
            var5.printStackTrace();
            return false;
        }
    }

    private void generateFile(File file) throws IOException, TemplateException {
        this.generateTemplate(file);
    }

    private boolean isEntityDir(File file) {
        String filePath = file.getPath();
        return filePath.indexOf("${entityDir}") != -1 || filePath.indexOf("${entityName}") != -1;
    }

    private void generateTemplate(File templateFile) throws IOException, TemplateException {
        this.config.setTemplateLoader(new FileTemplateLoader(templateFile.getParentFile()));
        Template template = this.config.getTemplate(templateFile.getName());
        FileWriter fileWriter = new FileWriter(this.getDestFile(templateFile));
        template.process(this.paramsMap, fileWriter);
        fileWriter.flush();
        fileWriter.close();
    }

    private File getDestFile(File origFile) {
        String origRelativePath = FileHelper.getRelativePath(this.templateDir, origFile);
        if(FileHelper.getFileSuffix(origFile).equalsIgnoreCase("copy")) {
            origRelativePath = origRelativePath.substring(0, origRelativePath.indexOf(".copy"));
        } else if(FileHelper.getFileSuffix(origFile).equalsIgnoreCase("ftl")) {
            origRelativePath = origRelativePath.substring(0, origRelativePath.indexOf(".ftl"));
        }

        StringTemplate destPath = new StringTemplate(origRelativePath, this.paramsMap);
        File dest = new File(this.getDestDir().getPath() + SLASH + destPath.toString());
        File destDir = dest.getParentFile();
        if(!destDir.exists()) {
            destDir.mkdirs();
        }

        return dest;
    }

    private void createDir(File origDir) {
        if(this.isEntityDir(origDir)) {
            if(this.paramsMap.containsKey("tables")) {
                List tables = (List)this.paramsMap.get("tables");
                if(tables != null) {
                    Iterator var4 = tables.iterator();

                    while(var4.hasNext()) {
                        Map table = (Map)var4.next();
                        String entityName = (String)table.get("entityName");
                        this.addParam("entityDir", StringHelper.uncapitalize(entityName));
                        this.createDestDir(origDir);
                    }
                }
            }
        } else {
            this.createDestDir(origDir);
        }

    }

    private void createDestDir(File origDir) {
        String relativePath = FileHelper.getRelativePath(this.templateDir, origDir);
        StringTemplate template = new StringTemplate(relativePath, this.paramsMap);
        String newPath = this.getDestDir().getPath() + SLASH + template.toString();
        File newDir = new File(newPath);
        if(!newDir.exists()) {
            newDir.mkdirs();
        }

    }

    public void cleanGeneratedCode() {
        FileUtil.deleteFile(this.getDestDir());
    }
}

